package com.zhang.boot.core.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.zhang.boot.core.constants.ApiConstant;
import com.zhang.boot.core.constants.ErrorEnum;
import com.zhang.boot.core.entity.Menu;
import com.zhang.boot.core.entity.Role;
import com.zhang.boot.core.entity.User;
import com.zhang.boot.core.service.MenuService;
import com.zhang.boot.core.service.RoleService;
import com.zhang.boot.core.service.UserService;
import com.zhang.boot.core.util.AssertUtil;
import com.zhang.boot.core.vo.LoginUser;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@Transactional(rollbackFor = Exception.class)
@Slf4j
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
    private final UserService userService;
    private final MenuService menuService;
    private final RoleService roleService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userService.getByAccount(username);
        AssertUtil.notEmpty(user, ErrorEnum.ACCOUNT_ERROR);
        List<Role> roleList = roleService.listByUserId(user.getUserId());
        user.setRoles(roleList);
        AssertUtil.isTrue(ApiConstant.ZERO == user.getStatus(), ErrorEnum.ACCOUNT_LOCK);
        userService.checkAdmin(user);
        return createLoginUser(user);
    }

    public UserDetails createLoginUser(User user) {
        Set<String> perms = new HashSet<>();
        if (user.isAdmin()) {
            perms.add("*:*:*");
        } else {
            List<Menu> menuList = menuService.listByUser(user);
            if (CollUtil.isNotEmpty(menuList)) {
                perms = menuList.stream()
                        .map(Menu::getPerms)
                        .filter(StrUtil::isNotBlank)
                        .collect(Collectors.toSet());
            }
        }
        return new LoginUser(user, perms);
    }
}
